/**
 * Created by zyy on 15/7/9.
 * zhangyuyu@superjia.com
 */
(function (window) {
    var supportPushState = 'pushState' in history, evt = supportPushState ? 'popstate' : 'hashchange';

    var regexps = [
            /[\-{}\[\]+?.,\\\^$|#\s]/g,
            /\((.*?)\)/g,
            /(\(\?)?:\w+/g,
            /\*\w+/g,
        ],
        getRegExp = function (route) {
            route = route.replace(regexps[0], '\\$&')
                .replace(regexps[1], '(?:$1)?')
                .replace(regexps[2], function (match, optional) {
                    return optional ? match : '([^/?]+)'
                }).replace(regexps[3], '([^?]*?)');
            return new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$');
        },
        extractParams = function (route, fragment) {
            var params = route.exec(fragment).slice(1);
            var results = [], i;
            for (i = 0; i < params.length; i++) {
                results.push(decodeURIComponent(params[i]) || null);
            }
            return results;
        };

    function Router(opts) {
        var self = this;
        self.opts = opts;
        self.routes = opts.routes;
        self.root = opts.root;
        self.statefulClass = opts.statefulClass || 'stateful';
        self.search = location.search;
        self.hash = location.hash;
        self.stateful();
    }

    Router.prototype = {
        exec: function (path) {
            for (var r in this.routes) {
                var route = getRegExp(r);
                if (!route.test(path)) {
                    continue;
                }
                if (typeof this.routes[r] === 'function') {
                    this.routes[r].apply(this, extractParams(route, path));
                } else {
                    var fn = this.opts[this.routes[r]];
                    fn ? fn.apply(this, extractParams(route, path)) : void 0;
                }
            }
        },
        emit: function (evt) {
            var self = this;
            var root = self.root;
            var fullpath = evt.state.path;

            if (root) {
                path = fullpath.replace(root, '');
            }

            this.exec(path);
        },
        start: function () {
            var self = this;
            var opts = self.opts;
            self.go(location.pathname.replace(opts.root || '', ''), true);
            if (!supportPushState) return false;
            window.addEventListener ? window.addEventListener(evt, function (path) {
                self.emit(path);
            }, false) : window.attachEvent('on' + evt, function (path) {
                self.emit(path)
            })
        },
        stop: function () {
            var self = this;
            if (!supportPushState) return false;
            window.removeEventListener ? window.removeEventListener(evt, function (path) {
                self.emit(path);
            }, false) : window.detachEvent('on' + evt, function (path) {
                self.emit(path);
            });
        },
        go: function (path, isReplace) {
            var self = this;
            if (!supportPushState) {
                this.exec(path);
                return false;
            }
            var root = self.root;
            var fullpath = path;
            if (root) {
                fullpath = root + path
            }
            if (history.state && fullpath === history.state.path) {
                isReplace = true;
            }
            //支持?参数
            fullpath += self.search || '';
            //支持#参数
            fullpath += self.hash || '';
            if (isReplace) {
                history.replaceState({path: fullpath}, document.title, fullpath);
            } else {
                history.pushState({path: fullpath}, document.title, fullpath);
            }
            this.exec(path);
        },
        back: function () {
            history.back();
        },
        stateful: function() {
            var self = this;
            if(!$) return false;

            $(document).on('click', '.' + self.statefulClass, function() {
                var item = $(this);
                var url = item.attr('href');
                if(url)
                    self.go(url);
                return false;
            });
        }
    };

    App.common.Router = Router;

    //使用例子
    /*var router = new Router({
        root: '/mock',
        routes: {
            '': function() {
                document.getElementById('out').innerHTML = 'You click mock';
            },
            '/': function() {
                document.getElementById('out').innerHTML = 'You click /';
            },

            '/todo': 'todo',
            '/start/:id': 'start',
            '/pages/p:page': 'page',
            '/files/*path': 'file',
            '/go': 'go'
        },

        todo: function() {
            document.getElementById('out').innerHTML = 'You click TODO';
        },
        start: function(id) {
            document.getElementById('out').innerHTML = 'You click identifier, identifier is <span style="color:red;">' + id + '</span>';
        },
        page: function(num) {
            document.getElementById('out').innerHTML = 'You click identifier, Page is <span style="color:red;">' + num + '</span>';
        },
        file: function(path) {
            document.getElementById('out').innerHTML = 'You click Path, path is <span style="color:red;">' + path + '</span>';
        },
        go: function() {
            router.go('/start/654321');
        }
    });
    router.start();*/
})(window);